package org.example;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public abstract class Parser {
    protected final Lexer input; // 词法解析器
    protected final List<Token> lookahead;
    protected final Stack<Integer> markers; // 存放上次p的位置
    protected int p; // 当前向前看词法单元的下标

    public Parser(Lexer input) {
        this.input = input;
        lookahead = new ArrayList<>();
        markers = new Stack<>();
        p = 0;
        sync(1);
    }

    // 返回向前看的第i个词法单元（i从1开始）
    public Token LT(int i) {
        sync(i);
        return lookahead.get(p + i - 1);
    }

    // 返回向前看第i个词法单元的类型
    public int LA(int i) {
        return LT(i).type;
    }

    public void match(int type) {
        if (LA(1) == type) {
            consume();
        } else {
            throw new RecognitionException("期望:" + input.getTokenName(type) + ", 实际:" + LT(1));
        }
    }

    public void consume() {
        p++;

        // 非推断状态，而且达到向前看缓冲区的末尾
        if (p == lookahead.size() && !isSpeculating())
        {
            // 到了末尾，就该重新从0开始填入新的词法单元
            p = 0;
            lookahead.clear(); // 大小清0，但不回收内存
        }

        sync(1); // 取一个新的词法单元
    }

    // 确保当前位置p之前有i个词法单元
    public void sync(int i) {
        if (p + i - 1 < lookahead.size()) {
            return;
        }

        var count = lookahead.size() + 1;
        for (var current = p + i - 1; current < count; current++) {
            lookahead.add(input.nextToken());
        }
    }

    public void mark() {
        markers.push(p);
    }

    public void release() {
        p = markers.pop();
    }

    public boolean isSpeculating() {
        return !markers.empty();
    }

}
